package cz.cvut.fel.taskpro.data.entity;

import cz.cvut.fel.taskpro.business.support.Maintance;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.OrderColumn;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;


/**
 * This entity represents assignment which is assigned to group, student or team.
 * @author Tom
 * @version 1.0.0 beta
 */
@Entity
@Table(name = "assignment")
@NamedQueries({
    @NamedQuery(name = "Assignment.findByStudent", query = "SELECT a FROM Assignment a WHERE a.mStudents = :student"),
    @NamedQuery(name = "Assignment.findByTeam", query = "SELECT a FROM Assignment a WHERE a.mTeams = :team"),
    @NamedQuery(name = "Assignment.findByGroup", query = "SELECT a FROM Assignment a WHERE a.mGroups = :groupTaskPro"),
    //  @NamedQuery(name = "Assignment.findAllStudents",
    //    query = "SELECT a FROM Assignment a WHERE a.mGroups.mStudents = :student OR a.mStudents =: student OR  a.mTeams.mStudents=:student
    @NamedQuery(name = "Assignment.findByGroupNotSubmit", query = "SELECT a FROM Assignment a WHERE a.mGroups = :groupTaskPro AND a.assignmentSubmit=:assignment_submit")
})
public class Assignment implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    @Column(name = "id")
    private int id;
    @Column(name = "deadline")
    @Temporal(TemporalType.TIMESTAMP)
    private Date deadline;
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateOfStart;
    @Column(name = "dateOfAssignment")
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateOfAssignment;
    @ManyToMany(mappedBy = "mAssignments", fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST})
    private List<Team> mTeams;
    @ManyToMany(mappedBy="mAssignment",fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST})
    private List<Student> mStudents;
    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST}) //mozna dodelat do template bidircitonal
    @OrderBy("dateOfCreation ASC")
    private Template template;
    @OneToMany(mappedBy = "assignment", fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST})
    //@OrderBy("dateOfSubmit ASC")
    private List<AssignmentSubmit> assignmentSubmit;
    @ManyToMany(mappedBy = "mAssignments", fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST})
    private List<GroupTaskPro> mGroups;
    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST})
    private Subject subject;
    @Column(name = "type")
    private Assignment.Type type;
    private int maxScore;

    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    public void setDateOfAssignment(Date dateOfAssignment) {
        this.dateOfAssignment = dateOfAssignment;
    }

    public static enum Type {

        GROUP,
        STUDENT,
        TEAM,
    };

    public List<Team> getmTeams() {
        return mTeams;
    }

    public void setmTeams(List<Team> mTeams) {
        this.mTeams = mTeams;
    }

    public Assignment() {
        dateOfAssignment = Calendar.getInstance().getTime();
    }

    public Assignment(Date deadline, List<Team> mTeams, List<Student> mStudents, Template template, List<GroupTaskPro> mGroups, Type type, Subject subject) {
        this.deadline = deadline;
        this.mTeams = mTeams;
        this.mStudents = mStudents;
        this.template = template;
        this.mGroups = mGroups;
        this.type = type;
        dateOfAssignment = Maintance.getTodayDate();
        this.subject = subject;
    }

    public void setAssignmentSubmit(List<AssignmentSubmit> assignmentSubmit) {
        this.assignmentSubmit = assignmentSubmit;
    }

    public void setDeadline(Date deadline) {
        this.deadline = deadline;
    }

    public Date getDateOfAssignment() {
        return dateOfAssignment;
    }

    public Date getDeadline() {
        return deadline;
    }

    public int getId() {
        return id;
    }

    @OrderColumn(name = "code")
    public void setmGroups(List<GroupTaskPro> mGroups) {
        this.mGroups = mGroups;
    }

    public List<AssignmentSubmit> getAssignmentSubmit() {
        return assignmentSubmit;
    }

    /**
     * prida novy ukol k zadani
     *
     * @param u - novy ukol
     */
    public void addTask(AssignmentSubmit u) {
        if (assignmentSubmit == null) {
            assignmentSubmit = new ArrayList<AssignmentSubmit>();
        }
        assignmentSubmit.add(u);
    }

    /**
     * prida paralelku k zadani
     *
     * @param p - paralelka
     */
    public void addGroup(GroupTaskPro p) {
        if (this.mGroups == null) {
            mGroups = new ArrayList<GroupTaskPro>();
        }
        mGroups.add(p);
    }

    public List<GroupTaskPro> getmGroups() {
        return mGroups;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Assignment)) {
            return false;
        }
        Assignment other = (Assignment) object;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (int) id;
        return hash;
    }

    @Override
    public String toString() {
        return "DL.entity.Assignment[ id=" + id + " ]";
    }

    public Template getTemplate() {
        return template;
    }

    public void setTemplate(Template template) {
        this.template = template;
    }

    public List<Student> getmStudents() {
        return mStudents;
    }

    public void setmStudents(List<Student> mStudents) {
        this.mStudents = mStudents;
    }

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }

    public int getMaxScore() {
        return maxScore;
    }

    public void setMaxScore(int maxScore) {
        this.maxScore = maxScore;
    }

    public Date getDateOfStart() {
        return dateOfStart;
    }

    public void setDateOfStart(Date dateOfStart) {
        this.dateOfStart = dateOfStart;
    }
    
}